package com.jming.tenement.front.aop;

import com.alibaba.fastjson.JSON;
import com.jming.tenement.service.common.BusinessException;
import com.jming.tenement.service.common.ResponseCode;
import com.jming.tenement.service.common.ResponseResult;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.ServletRequest;

import static com.jming.tenement.service.common.ResponseCode.PARAM_EXCEPTION;

/**
 * @author jming
 */
@Slf4j
@Aspect
@Component
@RestControllerAdvice
public class ControllerAspect {

    @Pointcut("execution(* com.jming.tenement.front.controller.*.*(..))")
    public void controllerMethod() {
    }

    @Around("controllerMethod()")
    public Object process(ProceedingJoinPoint pjp) throws Throwable {
        Object result;
        try {
            Object[] args = pjp.getArgs();
            for (Object arg : args) {
                if (arg instanceof BindingResult) {
                    BindingResult re = (BindingResult) arg;
                    if (re.hasErrors()) {
                        String errorMsg = !ObjectUtils.isEmpty(re.getFieldError()) ? re.getFieldError().getDefaultMessage() : "参数错误";
                        result = new ResponseResult<>(PARAM_EXCEPTION.getCode(), errorMsg);
                        return result;
                    }
                }
            }
            Object obj = pjp.proceed();
            if (obj instanceof ResponseResult) {
                result = obj;
            } else {
                result = new ResponseResult<>(obj);
            }
        } catch (BusinessException e) {
            log.error("业务异常：" + e.getMessage(), e);
            result = new ResponseResult<>(ResponseCode.BUSINESS_EXCEPTION.getCode(), e.getMessage());
        } catch (Exception e) {
            log.error("系统异常：" + e.getMessage(), e);
            result = new ResponseResult<>(ResponseCode.SYSTEM_EXCEPTION.getCode(), ResponseCode.SYSTEM_EXCEPTION.getMessage());
        }
        writeLog(pjp, result);
        return result;
    }

    @ExceptionHandler
    @ResponseStatus(value = HttpStatus.BAD_REQUEST)
    public Object handleException(MethodArgumentNotValidException e) {
        FieldError fieldError = e.getBindingResult().getFieldError();

        String msg = "请求异常!";
        if (!ObjectUtils.isEmpty(fieldError)) {
            msg = fieldError.getField() + "-" + fieldError.getDefaultMessage();
        }

        ResponseResult<Object> result = new ResponseResult<>(PARAM_EXCEPTION.getCode(), msg);
        return new ResponseEntity<>(result, HttpStatus.OK);
    }

    @ExceptionHandler
    @ResponseStatus(value = HttpStatus.BAD_REQUEST)
    public Object handleException(MissingServletRequestParameterException e) {
        ResponseResult<Object> result = new ResponseResult<>(PARAM_EXCEPTION.getCode(), e.getMessage());
        return new ResponseEntity<>(result, HttpStatus.OK);
    }

    private void writeLog(ProceedingJoinPoint pjp, Object result) {
        try {
            MethodSignature signature = (MethodSignature) pjp.getSignature();
            String method = signature.getDeclaringTypeName() + "." + signature.getName();
            Object param = null;
            Object[] args = pjp.getArgs();
            if (args != null && args.length > 0) {
                if (args.length == 1) {
                    param = args[0];
                } else {
                    String[] argNames = signature.getParameterNames();
                    StringBuilder buf = new StringBuilder();
                    for (int i = 0; i < args.length; i++) {
                        if (args[i] instanceof ServletRequest) {
                            continue;
                        }
                        if (args[i] instanceof BindingResult) {
                            continue;
                        }

                        buf.append(argNames[i]).append("=").append(args[i]).append(" ");
                    }
                    param = buf.toString();
                }
            }
            log.debug("method:[{}], req:[{}], resp:[{}]", method, JSON.toJSONString(param), JSON.toJSONString(result));
        } catch (Exception e) {
            log.info("打印日志出错", e);
        }
    }
}